package parser;

/*
 * Parser for display
 * Takes in command from GUI.Main, and call appropriate method in display
 * 
 */

import java.util.ArrayList;

import logger.Logger;
import logic.Display;
import memory.GenericEvents;
import memory.Memory;

public class ParserDisplay extends ParserMain{

	private static final String SPACE = " ";
	private static final String TYPE_EVENT = "event";
	private static final String TYPE_DEADLINE = "deadline";
	private static final String TYPE_TASK = "task";

	private static final String STATUS_OVERDUE = "overdue";
	private static final String STATUS_ONGOING = "ongoing";
	private static final String STATUS_OVER = "over";
	private static final String STATUS_UPCOMING = "upcoming";
	private static final String STATUS_COMPLETED = "completed";
	private static final String STATUS_INCOMPLETE = "incomplete";

	private static final String ERROR_ITEM_NOT_FOUND = "No items found!";
	private static final String ERROR_INVALID_INDEX = "Invalid index called for!";
	private static final String ERROR_NOT_IN_LIST_VIEW = "Command available only in list view!";
	private static final String ERROR_NO_ITEMS_TO_DISPLAY = "No items to display!";

	private static final String MESSAGE_DISPLAY_ALL = "Display All";

	private static final int DISPLAY_ALL = 11;
	private static final int DISPLAY_TYPE = 12;
	private static final int DISPLAY_STATUS = 13;
	private static final int DISPLAY_ITEM = 15;

	//@author A0085082E
	/*
	 * Run display as called by GUI.Main
	 */
	public static void run(String command, Memory memory){
		initVar();
		setCommand(command);
		display(memory);
	}

	//@author A0085082E
	/*
	 * Initialising variables
	 */
	private static void initVar(){
		setCommand(null);
		setType(-1);
	}


	//@author A0085082E
	/*
	 * Takes in command and memory
	 * Set command type and call method corresponding to the command.
	 * If command is invalid, generate error message.
	 * 
	 */
	private static void display(Memory memory){

		String[] details = command.split(SPACE);

		setDisplayType(details);
		runCodeIfCommandIsValid(memory);
	}

	//@author A0085082E
	/*
	 * Check if command is valid
	 * If command is invalid, generate error message.
	 * If command is valid, run display
	 */
	private static void runCodeIfCommandIsValid(Memory memory) {
		switch (type) {
		case DISPLAY_ALL:
			displayAll(memory);
			break;

		case DISPLAY_ITEM:
			displayItem();
			break;

		case DISPLAY_TYPE:
			displayType(memory);
			break;

		case DISPLAY_STATUS:
			displayStatus(memory);
			break;

		default:

			generalError();
		}
	}

	//@author A0085082E
	/*
	 * Set command type
	 */
	private static void setDisplayType(String[] details){
		if(details.length == 1 && details[0].isEmpty()){
			setType(DISPLAY_ALL);
		}else if(isNumeric(command)){
			setType(DISPLAY_ITEM);
		}else if(details.length ==1 && isValidType(details[0]) ){
			setType(DISPLAY_TYPE);
		}else if(details.length==1 && isValidStatus(details[0])){
			setType(DISPLAY_STATUS);
		}
	}

	//@author A0085082E
	/*
	 * Display a list of every item available in memory
	 * Error message is generated if there are no item in the memory - no item has been added.
	 * 
	 */
	private static void displayAll(Memory memory) {
		if (memory.getSize() == 0) {
			System.out.println(ERROR_NO_ITEMS_TO_DISPLAY);
			Logger.add(LOGGER_ERROR + ERROR_NO_ITEMS_TO_DISPLAY);
		} else {
			Display.displayList(memory.getList(), MESSAGE_DISPLAY_ALL);
		}
	}

	//@author A0096677H
	/*
	 * Display item takes in an index that user request and display an item with that index
	 * Method checks that user is in list view and the index is actually within the list.
	 * If user is not in the list or index is out of bound, an error messaged is generated.
	 * 
	 */
	private static void displayItem() {
		int index = Integer.parseInt(command)-1;

		if (Display.listView != null && Display.listView.size() > index) { 
			GenericEvents item = Display.listView.get(index);
			Display.displayClear();
			Display.displayDetailed(item);

		} else if(Display.listView  == null){ 
			System.out.println(ERROR_NOT_IN_LIST_VIEW);
			Logger.add(LOGGER_ERROR + ERROR_NOT_IN_LIST_VIEW);

		}else if(Display.listView.size() <= index){
			System.out.println(ERROR_INVALID_INDEX);
			Logger.add(LOGGER_ERROR + ERROR_INVALID_INDEX);
		}
	}

	//@author A0096677H
	/*
	 * Method display an item or a list of item that has user request type.
	 * If no item of the type is found, an error message is printed.
	 */
	private static void displayType(Memory memory){
		String type =  reduceToChar(command);
		ArrayList<GenericEvents> list = getListOfSameType(type, memory);
		if(list.size() == 0){
			System.out.println(ERROR_ITEM_NOT_FOUND);
			Logger.add(LOGGER_ERROR + ERROR_ITEM_NOT_FOUND);
		}else{
			Display.displayType(list ,type);

		}
	}

	//@author A0085082E
	/*
	 * Search through the entire memory for the item type that user request for.
	 * Returns an arraylist of GenericEvents that has the type requested.
	 * This list includes items regardless of their status.
	 * 
	 */
	public static ArrayList<GenericEvents> getListOfSameType(String type, Memory memory) {
		ArrayList<GenericEvents> exactType = new ArrayList<GenericEvents>();
		for (int i=0; i<memory.getSize(); i++) {
			if (memory.get(i).getType().toLowerCase().equals(type)) {
				exactType.add(memory.get(i));
			}
		}
		return exactType;
	}

	//@author A0085082E
	/*
	 * Method checks if user request for valid type. 
	 * Return true if type is one of the three available: event, deadline and task. 
	 */
	private static boolean isValidType(String type){
		String reducedString = reduceToChar(type);
		return reducedString.toLowerCase().equals(TYPE_EVENT)||
				reducedString.toLowerCase().equals(TYPE_DEADLINE)||
				reducedString.toLowerCase().equals(TYPE_TASK);
	}

	//@author A0085082E
	/*
	 * Method display an item or a list of item that has user request status.
	 * If no item of the status is found, an error message is printed.
	 */
	private static void displayStatus(Memory memory){
		String status =  reduceToChar(command);
		ArrayList<GenericEvents> list = getListOfSameStatus(status, memory);
		if(list.size() == 0){
			System.out.println(ERROR_ITEM_NOT_FOUND);
			Logger.add(LOGGER_ERROR + ERROR_ITEM_NOT_FOUND);
		}else{
			Display.displayType(list ,status);
		}
	}

	//@author A0085082E
	/*
	 * Search through the entire memory for the status that user request for.
	 * Returns an arraylist of GenericEvents that has the status requested
	 */
	private static ArrayList<GenericEvents> getListOfSameStatus(String status, Memory memory) {
		ArrayList<GenericEvents> exactStatus = new ArrayList<GenericEvents>();
		for (int i=0; i<memory.getSize(); i++) {
			if (memory.get(i).getStateType().toLowerCase().equals(status)) { 
				exactStatus.add(memory.get(i));
			}
		}
		return exactStatus;
	}

	//@author A0085082E
	/*
	 * Method checks if user request for valid status.
	 * Return true if status are the four in use by the system.
	 */
	private static boolean isValidStatus(String status){
		String reducedString = reduceToChar(status);
		return reducedString.toLowerCase().equals(STATUS_INCOMPLETE)||
				reducedString.toLowerCase().equals(STATUS_COMPLETED)||
				reducedString.toLowerCase().equals(STATUS_UPCOMING)||
				reducedString.toLowerCase().equals(STATUS_ONGOING)||
				reducedString.toLowerCase().equals(STATUS_OVERDUE)||
				reducedString.toLowerCase().equals(STATUS_OVER);
	}



}
